﻿using System;
using System.Globalization;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Xml;
using Blackbird.Common.Properties;
using Blackbird.Common.Utility;
using Blackbird.Core.Editable.Base;

namespace Blackbird.Core.Editable.Frames
{
    public class EditableFrame : BaseEditableEntity, IComparable<EditableFrame>
    {
        public const int DefaultWidth = 64;
        public const int DefaultHeight = 64;
        public const double DefaultDpiX = 96.0;
        public const double DefaultDpiY = 96.0;
        private double _assignedDpiX;
        private double _assignedDpiY;
        private int _assignedHeight;
        private int _assignedWidth;

        public EditableFrame()
        {
            _assignedHeight = DefaultHeight;
            _assignedWidth = DefaultWidth;
            _assignedDpiX = DefaultDpiX;
            _assignedDpiY = DefaultDpiY;
            int stride = ((_assignedWidth*32) + 7/8);
            var content = new byte[_assignedHeight*stride];
            BitmapSource = CreateBitmapSource(content);
        }

        public EditableFrameset ParentFrameset { get; set; }

        private BitmapSource _bitmapSource;

        public BitmapSource BitmapSource
        {
            get { return _bitmapSource; }
            set
            {

                if (_bitmapSource != value)
                {
                    _bitmapSource = value;
                    InvokePropertyChanged("BitmapSource");
                }
            }
        }

        public int Index { get; set; }
        public override string TypeName
        {
            get { return Resources.EditableFrameTypeFriendlyName; }
        }

        public int Width
        {
            get { return BitmapSource == null ? 0 : BitmapSource.PixelWidth; }
        }

        public int Height
        {
            get { return BitmapSource == null ? 0 : BitmapSource.PixelHeight; }
        }

        public double DpiX
        {
            get { return BitmapSource == null ? 0 : BitmapSource.DpiX; }
        }

        public double DpiY
        {
            get { return BitmapSource == null ? 0 : BitmapSource.DpiY; }
        }

        public byte[] CollisionData { get; set; }

        #region IComparable<EditableFrame> Members

        public int CompareTo(EditableFrame other)
        {
            return Index.CompareTo(other.Index);
        }

        #endregion

        public void AutoGenerateCollisionData(CollisionDataAutoGenerationMode mode, int offset)
        {
            var imageData = new byte[BitmapSource.PixelWidth*BitmapSource.PixelHeight*4];
            CollisionData = new byte[BitmapSource.PixelWidth*BitmapSource.PixelHeight];
            int stride = ((BitmapSource.PixelWidth*32) + 7)/8;
            BitmapSource.CopyPixels(imageData, stride, 0);

            const long collisionDataIndex = 0;

            for (long index = 0; index < imageData.Length; index += 4)
            {
                byte b = imageData[index];
                byte g = imageData[index + 1];
                byte r = imageData[index + 2];
                byte a = imageData[index + 3];
                int currentValue = 0;
                switch (mode)
                {
                    case CollisionDataAutoGenerationMode.Blue:
                        currentValue = b - offset;
                        break;
                    case CollisionDataAutoGenerationMode.Green:
                        currentValue = g - offset;
                        break;
                    case CollisionDataAutoGenerationMode.Red:
                        currentValue = r - offset;
                        break;
                    case CollisionDataAutoGenerationMode.Alpha:
                        currentValue = a - offset;
                        break;
                }
                CollisionData[collisionDataIndex] = (byte) (Math.Min(Math.Max(0, currentValue), 255));
            }
        }

        protected override void ReadXmlAttributes(XmlReader reader)
        {
            Index = SerializationUtility.ReadAttribute(reader, "index", 0);
            _assignedWidth = SerializationUtility.ReadAttribute(reader, "width", DefaultWidth);
            _assignedHeight = SerializationUtility.ReadAttribute(reader, "height", DefaultHeight);
            _assignedDpiX = SerializationUtility.ReadAttribute(reader, "dpix", DefaultDpiX);
            _assignedDpiY = SerializationUtility.ReadAttribute(reader, "dpiy", DefaultDpiY);
        }

        protected override void ReadXmlContent(XmlReader reader)
        {
            byte[] content = Convert.FromBase64String(SerializationUtility.ReadElement(reader, "content", string.Empty));
            BitmapSource = CreateBitmapSource(content);
        }

        protected override void WriteXmlAttributes(XmlWriter writer)
        {
            writer.WriteAttributeString("index", Index.ToString(CultureInfo.CurrentCulture));
            writer.WriteAttributeString("width", Width.ToString(CultureInfo.CurrentCulture));
            writer.WriteAttributeString("height", Height.ToString(CultureInfo.CurrentCulture));
            writer.WriteAttributeString("dpix", BitmapSource.DpiX.ToString(CultureInfo.CurrentCulture));
            writer.WriteAttributeString("dpiy", BitmapSource.DpiY.ToString(CultureInfo.CurrentCulture));
        }

        protected override void WriteXmlContent(XmlWriter writer)
        {
            writer.WriteElementString("content", Convert.ToBase64String(GetBitmapBytes()));
        }

        private BitmapSource CreateBitmapSource(byte[] content)
        {
            int stride = ((_assignedWidth*32) + 7)/8;
            return BitmapSource.Create(_assignedWidth, _assignedHeight, _assignedDpiX, _assignedDpiY, PixelFormats.Bgra32,
                                       null, content, stride);
        }

        public byte[] GetBitmapBytes()
        {
            int stride = ((BitmapSource.PixelWidth * 32) + 7) / 8;
            var content = new byte[BitmapSource.PixelHeight * stride];
            BitmapSource.CopyPixels(content, stride, 0);
            return content;
        }
    }

    public enum CollisionDataAutoGenerationMode
    {
        Alpha,
        Red,
        Green,
        Blue
    }
}